package com.kaizeli.website.config;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.ZoneId;

/**
 * 自定义类型处理器：处理 LONG 类型到 LocalDateTime 的转换
 * 解决 MySQL 数据库中时间戳字段与 Java LocalDateTime 类型不匹配的问题
 */
@MappedTypes(LocalDateTime.class)
@MappedJdbcTypes(JdbcType.BIGINT)
public class LongToLocalDateTimeTypeHandler extends BaseTypeHandler<LocalDateTime> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, LocalDateTime parameter, JdbcType jdbcType) throws SQLException {
        // 将 LocalDateTime 转换为时间戳（毫秒）
        long timestamp = parameter.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
        ps.setLong(i, timestamp);
    }

    @Override
    public LocalDateTime getNullableResult(ResultSet rs, String columnName) throws SQLException {
        // 尝试多种方式获取时间值
        Object value = rs.getObject(columnName);
        return convertToLocalDateTime(value);
    }

    @Override
    public LocalDateTime getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        // 尝试多种方式获取时间值
        Object value = rs.getObject(columnIndex);
        return convertToLocalDateTime(value);
    }

    @Override
    public LocalDateTime getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        // 尝试多种方式获取时间值
        Object value = cs.getObject(columnIndex);
        return convertToLocalDateTime(value);
    }

    /**
     * 将各种类型的时间值转换为 LocalDateTime
     */
    private LocalDateTime convertToLocalDateTime(Object value) {
        if (value == null) {
            return null;
        }

        try {
            if (value instanceof Long) {
                // 处理时间戳（毫秒）
                long timestamp = (Long) value;
                return LocalDateTime.ofInstant(
                    java.time.Instant.ofEpochMilli(timestamp),
                    ZoneId.systemDefault()
                );
            } else if (value instanceof Integer) {
                // 处理 Integer 类型的时间戳（秒）
                long timestamp = ((Integer) value).longValue() * 1000;
                return LocalDateTime.ofInstant(
                    java.time.Instant.ofEpochMilli(timestamp),
                    ZoneId.systemDefault()
                );
            } else if (value instanceof Timestamp) {
                // 处理 Timestamp 类型
                return ((Timestamp) value).toLocalDateTime();
            } else if (value instanceof java.sql.Date) {
                // 处理 Date 类型
                return ((java.sql.Date) value).toLocalDate().atStartOfDay();
            } else if (value instanceof java.util.Date) {
                // 处理 java.util.Date 类型
                return LocalDateTime.ofInstant(
                    ((java.util.Date) value).toInstant(),
                    ZoneId.systemDefault()
                );
            } else if (value instanceof String) {
                // 处理字符串类型
                String strValue = (String) value;
                if (strValue.matches("\\d+")) {
                    // 如果是纯数字字符串，当作时间戳处理（毫秒）
                    long timestamp = Long.parseLong(strValue);
                    return LocalDateTime.ofInstant(
                        java.time.Instant.ofEpochMilli(timestamp),
                        ZoneId.systemDefault()
                    );
                } else {
                    // 尝试解析为标准格式
                    try {
                        return LocalDateTime.parse(strValue);
                    } catch (Exception e1) {
                        // 尝试其他日期格式
                        try {
                            return LocalDateTime.parse(strValue, 
                                java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                        } catch (Exception e2) {
                            // 如果都失败，抛出异常
                            throw new RuntimeException("无法解析日期字符串: " + strValue, e2);
                        }
                    }
                }
            } else {
                // 尝试转换为字符串再解析
                String strValue = value.toString();
                if (strValue.matches("\\d+")) {
                    // 如果是纯数字字符串，当作时间戳处理（毫秒）
                    long timestamp = Long.parseLong(strValue);
                    return LocalDateTime.ofInstant(
                        java.time.Instant.ofEpochMilli(timestamp),
                        ZoneId.systemDefault()
                    );
                } else {
                    // 尝试解析为标准格式
                    try {
                        return LocalDateTime.parse(strValue);
                    } catch (Exception e1) {
                        // 尝试其他日期格式
                        try {
                            return LocalDateTime.parse(strValue, 
                                java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                        } catch (Exception e2) {
                            // 如果都失败，抛出异常
                            throw new RuntimeException("无法解析日期字符串: " + strValue, e2);
                        }
                    }
                }
            }
        } catch (Exception e) {
            // 如果转换失败，记录日志并返回 null
            System.err.println("时间类型转换失败: " + value + ", 类型: " + value.getClass().getName() + ", 错误: " + e.getMessage());
            e.printStackTrace();
            return null;
        }
    }
}